﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Shapes;
using ButtonBuilder.Plugin;

namespace ButtonBuilder
{
    /// <summary>
    /// Interaction logic for PluginSettingsDialog.xaml
    /// </summary>
    public partial class PluginSettingsDialog : Window
    {
        public PluginSettingsDialog()
        {
            InitializeComponent();
            CommandBindings.Add(
                new CommandBinding(ApplicationCommands.Close,
                new ExecutedRoutedEventHandler((sender, args) =>
                {
                    this.Close();
                })));

            this.SourceInitialized += new EventHandler(InitializeWindowSource);
        }

        private IPlugin Plugin { get; set; }

        private Dictionary<ActionParam, TextBox> Fields { get; set; }

        private void LoadPlugin(IPlugin plugin)
        {
            Plugin = plugin;
            Title = Plugin.Name + " Settings";
            Fields = new Dictionary<ActionParam, TextBox>();

            ParameterTable.Children.Clear();
            ParameterTable.RowDefinitions.Clear();

            for (int row = 0; row < plugin.Parameters.Count; row++)
            {
                RowDefinition rowDef = new RowDefinition();
                ParameterTable.RowDefinitions.Add(rowDef);

                ActionParam parameter = plugin.Parameters[row];

                TextBlock label = new TextBlock();
                label.Text = parameter.Name + ":";
                label.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
                Grid.SetColumn(label, 0);
                Grid.SetRow(label, row);
                ParameterTable.Children.Add(label);

                TextBox field = new TextBox();
                field.Tag = parameter.Name;
                field.Text = parameter.Value;
                field.Margin = new Thickness(0, 0, 8, 0);
                field.TabIndex = row;
                Grid.SetColumn(field, 1);
                Grid.SetRow(field, row);
                ParameterTable.Children.Add(field);

                Fields.Add(parameter, field);

                if (parameter.Type.Equals(typeof(System.IO.File).FullName))
                {
                    field.IsReadOnly = true;
                    field.GotFocus += new RoutedEventHandler(HandleFileInputFocus);
                }
            }

            int tabIndex = plugin.Parameters.Count;
            btnOK.TabIndex = ++tabIndex;
            btnCancel.TabIndex = ++tabIndex;
            btnClose.TabIndex = ++tabIndex;
        }

        private void HandleFileInputFocus(object sender, RoutedEventArgs e)
        {
            TextBox input = sender as TextBox;

            var dlg = new System.Windows.Forms.OpenFileDialog();
            dlg.Multiselect = false;

            if (dlg.ShowDialog(this.GetIWin32Window()) == System.Windows.Forms.DialogResult.OK)
            {
                input.Text = dlg.FileName;
            }

            //Need a way to lose the focus on the input field, 
            //so this event gets called on the next click.
            btnOK.Focus();
        }

        private void btnCancel_Click(object sender, RoutedEventArgs e)
        {
            DialogResult = false;
            Close();
        }

        private void btnOK_Click(object sender, RoutedEventArgs e)
        {
            foreach (UIElement element in ParameterTable.Children)
            {
                if (element is TextBox)
                {
                    TextBox paramTextBox = element as TextBox;
                    string paramName = paramTextBox.Tag as string;

                    Plugin.PutStringParam(paramName, paramTextBox.Text);
                }
            }

            DialogResult = true;
            Close();
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            ActionParam firstParameter = Plugin.Parameters.First();

            //If the first parameter is a string type, auto select it for convenience.
            if (firstParameter.Type.Equals(typeof(String).FullName))
            {
                TextBox fieldControl = Fields[firstParameter];
                fieldControl.Focus();
            }
        }

        public static bool ShowDialog(Window owner, IPlugin plugin)
        {
            if (plugin.Parameters.Count == 0)
                throw new ApplicationException("Plugin does not specify any parameters.");

            PluginSettingsDialog dialog = new PluginSettingsDialog();

            dialog.Owner = owner;
            dialog.LoadPlugin(plugin);

            return dialog.ShowDialog().GetValueOrDefault();
        }

        #region Resizable/Dragging Window Helpers
        private const int WM_SYSCOMMAND = 0x112;
        private HwndSource hwndSource;
        private IntPtr retInt = IntPtr.Zero;

        private void InitializeWindowSource(object sender, EventArgs e)
        {
            hwndSource = PresentationSource.FromVisual((Visual)sender) as HwndSource;
            hwndSource.AddHook(new HwndSourceHook(WndProc));
        }

        public void DragWindow(object sender, MouseButtonEventArgs args)
        {
            DragMove();
        }

        private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
        {
            return IntPtr.Zero;
        }

        public enum ResizeDirection
        {
            Left = 1,
            Right = 2,
            Top = 3,
            TopLeft = 4,
            TopRight = 5,
            Bottom = 6,
            BottomLeft = 7,
            BottomRight = 8,
        }

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        private static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

        private void ResizeWindow(ResizeDirection direction)
        {
            SendMessage(hwndSource.Handle, WM_SYSCOMMAND, (IntPtr)(61440 + direction), IntPtr.Zero);
        }

        private void ResetCursor(object sender, MouseEventArgs e)
        {
            if (Mouse.LeftButton != MouseButtonState.Pressed)
            {
                this.Cursor = Cursors.Arrow;
            }
        }

        private void Resize(object sender, MouseButtonEventArgs e)
        {
            Rectangle clickedRectangle = sender as Rectangle;

            switch (clickedRectangle.Name)
            {
                case "top":
                    this.Cursor = Cursors.SizeNS;
                    ResizeWindow(ResizeDirection.Top);
                    break;
                case "bottom":
                    this.Cursor = Cursors.SizeNS;
                    ResizeWindow(ResizeDirection.Bottom);
                    break;
                case "left":
                    this.Cursor = Cursors.SizeWE;
                    ResizeWindow(ResizeDirection.Left);
                    break;
                case "right":
                    this.Cursor = Cursors.SizeWE;
                    ResizeWindow(ResizeDirection.Right);
                    break;
                case "topLeft":
                    this.Cursor = Cursors.SizeNWSE;
                    ResizeWindow(ResizeDirection.TopLeft);
                    break;
                case "topRight":
                    this.Cursor = Cursors.SizeNESW;
                    ResizeWindow(ResizeDirection.TopRight);
                    break;
                case "bottomLeft":
                    this.Cursor = Cursors.SizeNESW;
                    ResizeWindow(ResizeDirection.BottomLeft);
                    break;
                case "bottomRight":
                    this.Cursor = Cursors.SizeNWSE;
                    ResizeWindow(ResizeDirection.BottomRight);
                    break;
                default:
                    break;
            }
        }

        private void DisplayResizeCursor(object sender, MouseEventArgs e)
        {
            Rectangle clickedRectangle = sender as Rectangle;

            switch (clickedRectangle.Name)
            {
                case "top":
                    this.Cursor = Cursors.SizeNS;
                    break;
                case "bottom":
                    this.Cursor = Cursors.SizeNS;
                    break;
                case "left":
                    this.Cursor = Cursors.SizeWE;
                    break;
                case "right":
                    this.Cursor = Cursors.SizeWE;
                    break;
                case "topLeft":
                    this.Cursor = Cursors.SizeNWSE;
                    break;
                case "topRight":
                    this.Cursor = Cursors.SizeNESW;
                    break;
                case "bottomLeft":
                    this.Cursor = Cursors.SizeNESW;
                    break;
                case "bottomRight":
                    this.Cursor = Cursors.SizeNWSE;
                    break;
                default:
                    break;
            }
        }
        #endregion
    }
}
